home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / sgml / msdos / sgml07 / modmd1.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-14  |  27.3 KB  |  753 lines

  1. #include "sgmlincl.h"         /* #INCLUDE statements for SGML parser. */
  2. /* MDADL: Process ATTLIST declaration.
  3. */
  4. VOID mdadl(tbuf)
  5. UNCH *tbuf;                   /* Work area for tokenization (tbuf). */
  6. {
  7.      int i;                   /* Loop counter; temporary variable. */
  8.      int adlim;               /* Number of unused ad slots in al. */
  9.      struct ad *alperm = 0;   /* Attribute definition list. */
  10.  
  11.      mdname = key[KATTLIST];  /* Identify declaration for messages. */
  12.      subdcl = 0;              /* No subject as yet. */
  13.      parmno = 0;              /* No parameters as yet. */
  14.      mdessv = es;             /* Save es level for entity nesting check. */
  15.      reqadn = noteadn = 0;    /* No required attributes yet. */
  16.      idadn = conradn = 0;     /* No special atts yet.*/
  17.      AN(al) = 0;                  /* Number of attributes defined. */
  18.      ADN(al) = 0;                 /* Number of ad's in al (atts + name vals).*/
  19.      /* PARAMETER 1: Element name or a group of them.
  20.      */
  21.      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  22.      TRACEMD("1: element name or group");
  23.      switch (pcbmd.action) {
  24.      case NAS:
  25.           nmgrp[0] = etddef(tbuf);
  26.           nmgrp[1] = 0;
  27.           break;
  28.      case GRPS:
  29.           parsegrp(nmgrp, &pcbgrnm, tbuf);
  30.           break;
  31.      case RNS:           /* Reserved name started. */
  32.           if (ustrcmp(tbuf+1, key[KNOTATION])) {
  33.                mderr(118, tbuf+1, key[KNOTATION]);
  34.                return;
  35.           }
  36.           mdnadl(tbuf);
  37.           return;
  38.      default:
  39.           mderr(121, (UNCH *)0, (UNCH *)0);
  40.           return;
  41.      }
  42.      subdcl = nmgrp[0]->etdgi+1;        /* Save first GI for error msgs. */
  43.      /* PARAMETER 2: Attribute definition list.
  44.      */
  45.      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  46.      TRACEMD("2: attribute list");
  47.      if (pcbmd.action!=NAS) {
  48.           mderr(120, (UNCH *)0, (UNCH *)0);
  49.           return;
  50.      }
  51.      while (pcbmd.action==NAS) {
  52.       al[ADN(al)+1].adname = savenm(tbuf);
  53.           if ((adlim = ATTCNT-((int)++ADN(al)))<0) {mderr(111, (UNCH *)0, (UNCH *)0); return;}
  54.           ++AN(al);
  55.           if (mdattdef(adlim, 0)) return;
  56.           parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  57.      }
  58.      if (AN(al)>0) {   /*  Save list only if 1 or more good atts. */
  59.           if (reqadn)  SET(ADLF(al), ADLREQ);    /* Element must have start-tag. */
  60.           if (noteadn) SET(ADLF(al), ADLNOTE);   /* Element cannot be EMPTY. */
  61.           if (conradn) SET(ADLF(al), ADLCONR);   /* Element cannot be EMPTY. */
  62.           alperm = (struct ad *)rmalloc((1+ADN(al))*ADSZ);
  63.           memcpy((UNIV)alperm, (UNIV)al, (1+ADN(al))*ADSZ );
  64.           ds.attcnt += AN(al);         /* Number of attributes defined. */
  65.           ds.attgcnt += ADN(al) - AN(al);  /* Number of att grp members. */
  66.           TRACEADL(alperm);
  67.      }
  68.      /* Clear attribute list for next declaration. */
  69.      MEMZERO((UNIV)al, (1+ADN(al))*ADSZ);
  70.  
  71.      /* PARAMETER 3: End of declaration.
  72.      */
  73.      /* Next pcb.action was set during attribute definition loop. */
  74.      TRACEMD(emd);
  75.      if (pcbmd.action!=EMD) {mderr(126, (UNCH *)0, (UNCH *)0); return;}
  76.      if (es!=mdessv) synerr(37, &pcbmd);
  77.  
  78.      /* EXECUTE: Store the definition for each element name specified.
  79.      */
  80.      TRACEGRP(nmgrp);
  81.      for (i = -1; nmgrp[++i];) {
  82.           if (nmgrp[i]->adl) {     /* Error if an ADL exists. */
  83.                mderr(112, (UNCH *)0, (UNCH *)0);
  84.                continue;
  85.           }
  86.           nmgrp[i]->adl = alperm;  /* If virgin, store the adl ptr. */
  87.           if (alperm) etdadl(nmgrp[i]); /* Check for conflicts with ETD. */
  88.      }
  89. }
  90. /* ETDADL: Check compatibility between ETD and ADL.
  91. */
  92. VOID etdadl(p)
  93. struct etd *p;                /* Pointer to element type definition. */
  94. {
  95.      parmno = 0;
  96.      /* Minimizable element cannot have required attribute. */
  97.      if (GET(p->etdmin, SMO) && GET(p->adl[0].adflags, ADLREQ)) {
  98.           mderr(40, (UNCH *)0, (UNCH *)0);
  99.           RESET(p->etdmin, SMO);
  100.      }
  101.      /* Empty element cannot have NOTATION attribute.
  102.         Attribute is not removed (too much trouble), but we trap
  103.         attempts to specify it on the start-tag in adlval().
  104.      */
  105.      if (p->etdmod && GET(p->etdmod->ttype, MNONE)) {
  106.           if (GET(p->adl[0].adflags, ADLNOTE))
  107.                mderr(83, (UNCH *)0, (UNCH *)0);
  108.  
  109.           /* Empty element cannot have CONREF attribute.
  110.              Attribute is not removed because it just acts
  111.              like IMPLIED anyway.
  112.           */
  113.           if (GET(p->adl[0].adflags, ADLCONR))
  114.                mderr(85, (UNCH *)0, (UNCH *)0);
  115.      }
  116.      /* "O" should be specified for the end-tag minimization if the element
  117.     has a content reference attribute. */
  118.      if (OMITTAG==YES && GET(p->adl[0].adflags, ADLCONR)
  119.      && BITOFF(p->etdmin, EMO))
  120.       mderr(153, (UNCH *)0, (UNCH *)0);
  121. }
  122. /* MDNADL: Process ATTLIST declaration for notation.
  123.            TO DO: Pass deftab and dvtab as parameters so
  124.            that prohibited types can be handled by leaving
  125.            them out of the tables.
  126. */
  127. VOID mdnadl(tbuf)
  128. UNCH *tbuf;                   /* Work area for tokenization (tbuf). */
  129. {
  130.      int i;                   /* Loop counter; temporary variable. */
  131.      int adlim;               /* Number of unused ad slots in al. */
  132.      struct ad *alperm = 0;   /* Attribute definition list. */
  133.  
  134.      /* PARAMETER 1: Notation name or a group of them.
  135.      */
  136.      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  137.      TRACEMD("1: notation name or group");
  138.      switch (pcbmd.action) {
  139.      case NAS:
  140.           nnmgrp[0] = dcndef(tbuf);
  141.           nnmgrp[1] = 0;
  142.           break;
  143.      case GRPS:
  144.           parsngrp(nnmgrp, &pcbgrnm, tbuf);
  145.           break;
  146.      default:
  147.           mderr(121, (UNCH *)0, (UNCH *)0);
  148.           return;
  149.      }
  150.      subdcl = nnmgrp[0]->ename+1;        /* Save first name for error msgs. */
  151.      /* PARAMETER 2: Attribute definition list.
  152.      */
  153.      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  154.      TRACEMD("2: attribute list");
  155.      if (pcbmd.action!=NAS) {
  156.           mderr(120, (UNCH *)0, (UNCH *)0);
  157.           return;
  158.      }
  159.      while (pcbmd.action==NAS) {
  160.       al[ADN(al)+1].adname = savenm(tbuf);
  161.           if ((adlim = ATTCNT-((int)ADN(al)++))<0) {mderr(111, (UNCH *)0, (UNCH *)0); return;}
  162.           ++AN(al);
  163.           if (mdattdef(adlim, 1)) return;
  164.           parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  165.      }
  166.      if (AN(al)>0) {   /*  Save list only if 1 or more good atts. */
  167.           alperm = (struct ad *)rmalloc((1+ADN(al))*ADSZ);
  168.           memcpy((UNIV)alperm, (UNIV)al, (1+ADN(al))*ADSZ );
  169.           ds.attcnt += AN(al);         /* Number of attributes defined. */
  170.           ds.attgcnt += ADN(al) - AN(al);  /* Number of att grp members. */
  171.           TRACEADL(alperm);
  172.      }
  173.      /* Clear attribute list for next declaration. */
  174.      MEMZERO((UNIV)al, (1+ADN(al))*ADSZ);
  175.  
  176.      /* PARAMETER 3: End of declaration.
  177.      */
  178.      /* Next pcb.action was set during attribute definition loop. */
  179.      TRACEMD(emd);
  180.      if (pcbmd.action!=EMD) {mderr(126, (UNCH *)0, (UNCH *)0); return;}
  181.      if (es!=mdessv) synerr(37, &pcbmd);
  182.  
  183.      /* EXECUTE: Store the definition for each notation name specified.
  184.      */
  185.      TRACENGR(nnmgrp);
  186.      for (i = -1; nnmgrp[++i];) {
  187.           if (nnmgrp[i]->adl) {     /* Error if an ADL exists. */
  188.                mderr(112, (UNCH *)0, (UNCH *)0);
  189.                continue;
  190.           }
  191.           nnmgrp[i]->adl = alperm;  /* If virgin, store the adl ptr. */
  192.           TRACEDCN(nnmgrp[i]);
  193.      }
  194. }
  195. /* MDATTDEF: Process an individual attribute definition.
  196.              The attribute name is parsed by the caller.
  197.              Duplicate attributes are parsed, but removed from list.
  198.              Returns 0 if successful, otherwise returns 1.
  199. */
  200. int mdattdef(adlim, datt)
  201. int adlim;                    /* Remaining capacity of al (in tokens).*/
  202. int datt;              /* Non-zero if a data attribute. */
  203. {
  204.      int deftype;             /* Default value type: 0=not keyword. */
  205.      int errsw = 0;           /* 1=semantic error; ignore att. */
  206.      int novalsw = 0;         /* 1=semantic error; treat as IMPLIED. */
  207.      int attadn = (int)ADN(al);   /* Save ad number of this attribute. */
  208.      struct parse *grppcb = NULL; /* PCB for name/token grp parse. */
  209.      int errcode;             /* Error type returned by PARSEVAL, ANMTGRP. */
  210.      UNCH *advalsv;           /* Save area for permanent value ptr. */
  211.  
  212.      /* PARAMETER 1: Attribute name (parsed by caller).
  213.      */
  214.      TRACEMD("1: attribute name");
  215.      if (anmget((int)ADN(al)-1, al[attadn].adname)) {
  216.           errsw = 1;
  217.           mderr(99, ADNAME(al,attadn), (UNCH *)0);
  218.      }
  219.      ADNUM(al,attadn) = ADFLAGS(al,attadn) = ADLEN(al,attadn) = 0;
  220.      ADVAL(al,attadn) = 0; ADDATA(al,attadn).x = 0; ADTYPE(al,attadn) = ANMTGRP;
  221.      /* PARAMETER 2: Declared value.
  222.      */
  223.      parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);
  224.      TRACEMD("2: declared value");
  225.      switch (pcbmd.action) {
  226.      case NAS:                /* Keyword for value type. */
  227.           switch (ADTYPE(al,attadn) = (UNCH)mapsrch(dvtab, lbuf+1)) {
  228.           case 0:
  229.                mderr(100, ADNAME(al,attadn), lbuf+1);
  230.                return 1;
  231.           case ANOTEGRP:
  232.            if (datt) {
  233.             errsw = 1;
  234.             mderr(156, (UNCH *)0, (UNCH *)0);
  235.            }
  236.                else if (!noteadn) noteadn = ADN(al);
  237.                else {
  238.                     errsw = 1;
  239.                     mderr(101, ADNAME(al,attadn), (UNCH *)0);
  240.                }
  241.                grppcb = &pcbgrnm;         /* NOTATION requires name grp. */
  242.                parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);/* Get GRPO*/
  243.                break;
  244.           case AID:
  245.            if (datt) {
  246.             errsw = 1;
  247.             mderr(144, (UNCH *)0, (UNCH *)0);
  248.            }
  249.                else if (!idadn)
  250.             idadn = attadn;
  251.                else {
  252.                     errsw = 1;
  253.                     mderr(102, ADNAME(al,attadn), (UNCH *)0);
  254.                }
  255.                break;
  256.       case AIDREF:
  257.       case AIDREFS:
  258.            if (datt) {
  259.             errsw = 1;
  260.             mderr(155, (UNCH *)0, (UNCH *)0);
  261.            }
  262.            break;
  263.       case AENTITY:
  264.       case AENTITYS:
  265.            if (datt) {
  266.             errsw = 1;
  267.             mderr(154, (UNCH *)0, (UNCH *)0);
  268.            }
  269.            break;
  270.           }
  271.           break;
  272.      case GRPS:
  273.           grppcb = &pcbgrnt;           /* Normal grp is name token grp. */
  274.           break;
  275.      case EMD:
  276.           mderr(103, ADNAME(al,attadn), (UNCH *)0);
  277.           return 1;
  278.      default:
  279.           mderr(104, ADNAME(al,attadn), (UNCH *)0);
  280.           return 1;
  281.      }
  282.      /* PARAMETER 2A: Name token group.
  283.      */
  284.      if (grppcb != NULL) {
  285.       TRACEMD("2A: name group");
  286.           switch (pcbmd.action) {
  287.           case GRPS:               /* Name token list. */
  288.                SET(ADFLAGS(al,attadn), AGROUP);
  289.                /* Call routine to parse group, create ad entries in adl. */
  290.                errcode = anmtgrp(grppcb, al+attadn,
  291.                     (GRPCNT<adlim ? GRPCNT+1 : adlim+1),
  292.                     &al[attadn].adnum, (int)ADN(al));
  293.                if (errcode<=0) {
  294.                     mderr(105, ADNAME(al,attadn), (UNCH *)0);
  295.                     return 1;
  296.                }
  297.                ADN(al) += ADNUM(al,attadn);    /* Add grp size to total ad cnt.*/
  298.                break;
  299.           default:
  300.                mderr(106, ADNAME(al,attadn), (UNCH *)0);
  301.                return 1;
  302.           }
  303.      }
  304.      /* PARAMETER 3: Default value keyword.
  305.      */
  306.      parsemd(lbuf, AVALCASE,
  307.          (ADTYPE(al,attadn)==ACHARS) ? &pcblitr : &pcblitt, LITLEN);
  308.      TRACEMD("3: default keyword");
  309.      switch (pcbmd.action) {
  310.      case RNS:                /* Keyword. */
  311.           deftype = mapsrch(deftab, lbuf+1);
  312.           switch (deftype) {
  313.           case DFIXED:        /* FIXED */
  314.                SET(ADFLAGS(al,attadn), AFIXED);
  315.                parsemd(lbuf, AVALCASE,
  316.                (ADTYPE(al,attadn)==ACHARS) ? &pcblitr : &pcblitt,
  317.                LITLEN);  /* Real default. */
  318.                goto parm3x;   /* Go process specified value. */
  319.           case DCURR:         /* CURRENT: If ID, treat as IMPLIED. */
  320.                if (ADTYPE(al,attadn)==AID) {
  321.                     mderr(80, ADNAME(al,attadn), (UNCH *)0);
  322.                     break;
  323.                }
  324.            if (datt) {
  325.             mderr(157, (UNCH *)0, (UNCH *)0);
  326.             break;
  327.            }
  328.                SET(ADFLAGS(al,attadn), ACURRENT);
  329.                break;
  330.           case DREQ:          /* REQUIRED */
  331.                SET(ADFLAGS(al,attadn), AREQ); ++reqadn;
  332.                break;
  333.           case DCONR:         /* CONREF */
  334.                if (ADTYPE(al,attadn)==AID) {
  335.                     mderr(107, ADNAME(al,attadn), (UNCH *)0);
  336.                     break;
  337.                }
  338.            if (datt) {
  339.             mderr(158, (UNCH *)0, (UNCH *)0);
  340.             break;
  341.            }
  342.                SET(ADFLAGS(al,attadn), ACONREF); conradn = 1;
  343.           case DNULL:         /* IMPLIED */
  344.                break;
  345.           default:            /* Unknown keyword is an error. */
  346.                mderr(108, ADNAME(al,attadn), lbuf+1);
  347.                errsw = 1;
  348.           }
  349.           if (errsw) {--AN(al); ADN(al) = (UNCH)attadn-1;} /* Ignore erroneous att. */
  350.           return(0);
  351.      default:
  352.           break;
  353.      }
  354.      /* PARAMETER 3x: Default value (non-keyword).
  355.      */
  356.      parm3x:
  357.      TRACEMD("3x: default (non-keyword)");
  358. /*   if (ADTYPE(al,attadn)==AID) {    ** If ID, treat as IMPLIED. **
  359.           mderr(81, ADNAME(al,attadn), (UNCH *)0);
  360.           novalsw = 1;             ** Keep parsing to keep things straight. **
  361.      } */
  362.      switch (pcbmd.action) {
  363.      case LIT:                /* Literal. */
  364.      case LITE:               /* Literal. */
  365.           /* Null string (except CDATA) is error: msg and treat as IMPLIED. */
  366.           if (*lbuf == '\0' && ADTYPE(al,attadn)!=ACHARS) {
  367.                mderr(82, ADNAME(al,attadn), (UNCH *)0);
  368.                novalsw = 1;
  369.           }
  370.       break;
  371.      case NAS:                /* Name character string. */
  372.      case NMT:                /* Name character string. */
  373.      case NUM:                /* Number or number token string. */
  374.       dellen(lbuf);          /* Delete length byte */
  375.           break;
  376.      case EMD:
  377.           mderr(109, ADNAME(al,attadn), (UNCH *)0);
  378.           return 1;
  379.      default:
  380.           mderr(110, ADNAME(al,attadn), (UNCH *)0);
  381.           return 1;
  382.      }
  383.      if (errsw) {
  384.           --AN(al); ADN(al) = (UNCH)attadn-1;    /* Ignore erroneous att. */
  385.           return(0);
  386.      }
  387.      if (novalsw) return(0);
  388.  
  389.      /* PARAMETER 3y: Validate and store default value.
  390.      */
  391.      if (ADTYPE(al,attadn)==ACHARS) {
  392.           /* No more checking for CDATA value. */
  393.           ADNUM(al,attadn) = 0;             /* CDATA is 0 tokens. */
  394.           ADVAL(al,attadn) = savestr(lbuf);/* Store default; save ptr. */
  395.           ADLEN(al,attadn) = vallen(ADTYPE(al,attadn), ADNUM(al,attadn),
  396.                     ADVAL(al,attadn));
  397.           ds.attdef += ADLEN(al,attadn);
  398.           return 0;
  399.      }
  400.      /* Parse value and save token count (GROUP implies 1 token). */
  401.      advalsv = (UNCH *)rmalloc(ustrlen(lbuf)+2); /* Storage for tokenized value. */
  402.      errcode = parseval(lbuf, (UNS)ADTYPE(al,attadn), advalsv);
  403.      if (BITOFF(ADFLAGS(al,attadn), AGROUP)) ADNUM(al,attadn) = (UNCH)tokencnt;
  404.  
  405.      /* If value was invalid, or was a group member that was not in the group,
  406.         issue an appropriate message and set the error switch. */
  407.      if (errcode)
  408.           {sgmlerr((UNS)errcode, &pcbmd, ADNAME(al,attadn), lbuf); errsw = 1;}
  409.      else if ( BITON(ADFLAGS(al,attadn), AGROUP)
  410.           && !amemget(&al[attadn], (int)ADNUM(al,attadn), advalsv) ) {
  411.                sgmlerr(79, &pcbmd, ADNAME(al,attadn), advalsv+1);
  412.                errsw = 1;
  413.      }
  414.      /* For valid tokenized value, save it and update statistics. */
  415.      if (!errsw) {
  416.           ds.attdef +=
  417.            (ADLEN(al,attadn) = vallen(ADTYPE(al,attadn),
  418.                       (int)ADNUM(al,attadn),
  419.                       (ADVAL(al,attadn) = advalsv)));
  420.           return 0;
  421.      }
  422.      /* If value was bad, free the value's storage and treat as
  423.         IMPLIED or REQUIRED. */
  424.      frem((UNIV)advalsv);          /* Release storage for value. */
  425.      ADVAL(al,attadn) = NULL;         /* And make value NULL. */
  426.      return 0;
  427. }
  428. /* ANMTGRP: Parse a name or name token group, create attribute descriptors
  429.             for its members, and add them to the attribute descriptor list.
  430.             The parse either terminates or returns a good token, so no
  431.             switch is needed.
  432. */
  433. int anmtgrp(pcb, nt, grplim, adn, adsz)
  434. struct parse *pcb;            /* PCB for name or name token grp. */
  435. struct ad nt[];               /* Buffer for creating name token list. */
  436. int grplim;                   /* Maximum size of list (plus 1). */
  437. UNS *adn;              /* Ptr to number of names or tokens in grp. */
  438. int adsz;                     /* Size of att def list. */
  439. {
  440.      UNCH adtype = (UNCH)(pcb==&pcbgrnt ? ANMTGRP:ANOTEGRP);/*Attribute type.*/
  441.      int essv = es;           /* Entity stack level when grp started. */
  442.  
  443.      *adn = 0;                /* Group is empty to start. */
  444.      while (parse(pcb)!=GRPE && *adn<grplim) {
  445.           switch (pcb->action) {
  446.           case NAS_:          /* Name or name token (depending on pcb). */
  447.           case NMT_:
  448.                parsenm(lbuf, NAMECASE);
  449.            nt[*adn+1].adname = savenm(lbuf);
  450.                if (antvget((int)(adsz+*adn), nt[*adn+1].adname, (UNCH **)0))
  451.                     mderr(98, ntoa((int)*adn+1), nt[*adn+1].adname+1);
  452.                nt[++*adn].adtype = adtype;
  453.                nt[*adn].addef    = NULL;
  454.                continue;
  455.  
  456.           case EE_:           /* Entity ended (correctly or incorrectly). */
  457.                if (es<essv) {synerr(37, pcb); essv = es;}
  458.                continue;
  459.  
  460.           case PIE_:          /* PI entity reference (invalid). */
  461.                entpisw = 0;   /* Reset PI entity indicator. */
  462.                synerr(59, pcb);
  463.                continue;
  464.  
  465.           default:
  466.                break;
  467.           }
  468.           break;
  469.      }
  470.      if (es!=essv) synerr(37, pcb);
  471.      if (*adn==grplim) return -1;
  472.      else return *adn;        /* Return number of tokens. */
  473. }
  474. /* MDDTDS: Process start of DOCTYPE declaration (through MSO).
  475. */
  476. VOID mddtds(tbuf)
  477. UNCH *tbuf;                   /* Work area for tokenization[LITLEN+2]. */
  478. {
  479.      struct fpi fpicb;        /* Formal public identifier structure. */
  480.      union etext etx;         /* Ptr to entity text. */
  481.      UNCH estore = ESD;       /* Entity storage class. */
  482.      int emdsw = 0;           /* 1=end of declaration found; 0=not yet. */
  483.  
  484.      mdname = key[KDOCTYPE];  /* Identify declaration for messages. */
  485.      subdcl = NULL;           /* No subject as yet. */
  486.      parmno = 0;              /* No parameters as yet. */
  487.      mdessv = es;             /* Save es for checking entity nesting. */
  488.      dtdrefsw = 0;            /* No external DTD entity as yet. */
  489.      /* PARAMETER 1: Document type name.
  490.      */
  491.      pcbmd.newstate = 0;
  492.      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  493.      TRACEMD("1: doc type name");
  494.      if (pcbmd.action!=NAS) {mderr(120, (UNCH *)0, (UNCH *)0); return;}
  495.      dtype = savenm(tbuf);
  496.      subdcl = dtype+1;        /* Subject of declaration for error msgs. */
  497.  
  498.      /* PARAMETER 2: External identifier keyword or MDS.
  499.      */
  500.      pcbmd.newstate = 0;
  501.      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  502.      TRACEMD("2: extid or MDS");
  503.      switch (pcbmd.action) {
  504.      case NAS:
  505.           if (mdextid(tbuf, &fpicb, dtype+1, &estore, (PNE)0)==0) return;
  506.           if ((etx.x = entgen(&fpicb))==0) {mderr(146, dtype+1, (UNCH *)0); return;}
  507.           dtdrefsw = 1;            /* Signal external DTD entity. */
  508.           break;
  509.      case MDS:
  510.           goto execute;
  511.      default:
  512.           mderr(128, (UNCH *)0, (UNCH *)0);
  513.           return;
  514.      }
  515.      /* PARAMETER 3: MDS or end of declaration.
  516.      */
  517.      TRACEMD("3: MDS or EMD");
  518.      switch (pcbmd.action) {
  519.      default:                      /* Treat as end of declaration. */
  520.           mderr(126, (UNCH *)0, (UNCH *)0);
  521.      case EMD:
  522.           emdsw = 1;
  523.      case MDS:
  524.           break;
  525.      }
  526.      /* EXECUTE: Store entity definition if an external ID was specified.
  527.      */
  528.      execute:
  529.      if (es!=mdessv) synerr(37, &pcbmd);
  530.      propcb = &pcbmds;        /* Prepare to parse doc type definition (MDS). */
  531.      if (dtdrefsw) {
  532.       /* TO DO: If concurrent DTD's supported, free existing
  533.          etext for all but first DTD (or reuse it). */
  534.       entdef(indtdent, estore, &etx);
  535.       ++ds.ecbcnt; ds.ecbtext += entlen;
  536.           if (emdsw) {
  537.                REPEATCC;                /* Push back the MDC. */
  538.                *FPOS = lex.d.msc;       /* Simulate end of DTD subset. */
  539.                REPEATCC;                /* Back up to read MSC next. */
  540.                delmscsw = 1;            /* Insert MSC after referenced DTD. */
  541.           }
  542.      }
  543.      indtdsw = 1;                       /* Allow "DTD only" parameters. */
  544.      return;
  545. }
  546. /* MDDTDE: Process DOCTYPE declaration end.
  547. */
  548. VOID mddtde(tbuf)
  549. UNCH *tbuf;                   /* Work area for tokenization. */
  550. {
  551.      mdessv = es;             /* Save es for checking entity nesting. */
  552.      propcb = &pcbpro;        /* Restore normal prolog parse. */
  553.      indtdsw = 0;             /* Prohibit "DTD only" parameters. */
  554.  
  555.      mdname = key[KDOCTYPE];  /* Identify declaration for messages. */
  556.      subdcl = dtype+1;        /* Subject of declaration for error msgs. */
  557.      parmno = 0;              /* No parameters as yet. */
  558.      /* PARAMETER 4: End of declaration.
  559.      */
  560.      pcbmd.newstate = 0;
  561.      parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
  562.      TRACEMD(emd);
  563.      if (pcbmd.action!=EMD) mderr(126, (UNCH *)0, (UNCH *)0);
  564.      if (es!=mdessv) synerr(37, &pcbmd);
  565. }
  566. /* MDELEM: Process ELEMENT declaration.
  567. */
  568. VOID mdelem(tbuf)
  569. UNCH *tbuf;                   /* Work area for tokenization (tbuf). */
  570. {
  571.      UNCH *ranksuff = lbuf;   /* Rank suffix. */
  572.      UNS dctype = 0;          /* Declared content type (from dctab). */
  573.      UNCH fmin = 0;           /* Minimization bit flags. */
  574.      int i;                   /* Loop counter. */
  575.      UNS u;                   /* Temporary variable. */
  576.      struct etd **mexgrp, **pexgrp; /* Ptr to model exceptions array. */
  577.      struct thdr *cmod, *cmodsv;    /* Ptr to content model. */
  578.      UNCH *etdgi;             /* GI of current etd (when going through group).*/
  579.      int minomitted = 0;      /*  Tag minimization parameters omitted. */
  580.  
  581.      mdname = key[KELEMENT];  /* Identify declaration for messages. */
  582.      subdcl = NULL;           /* No subject as yet. */
  583.      parmno = 0;              /* No parameters as yet. */
  584.      mdessv = es;             /* Save es level for entity nesting check. */
  585.      ranksuff[0] = 0;
  586.      mexgrp = pexgrp = 0;
  587.  
  588.      /* PARAMETER 1: Element name or a group of them.
  589.      */
  590.      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  591.      TRACEMD("1: element name or grp");
  592.      switch (pcbmd.action) {
  593.      case NAS:
  594.           nmgrp[0] = etddef(tbuf);
  595.           nmgrp[1] = 0;
  596.           break;
  597.      case GRPS:
  598.           parsegrp(nmgrp, &pcbgrnm, tbuf);
  599.           break;
  600.      default:
  601.           mderr(121, (UNCH *)0, (UNCH *)0);
  602.           return;
  603.      }
  604.      /* Save first GI for trace and error messages. */
  605.      subdcl = nmgrp[0]->etdgi+1;
  606.  
  607.      /* PARAMETER 1A: Rank suffix (optional).
  608.      */
  609.      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  610.      TRACEMD("1A: rank suffix");
  611.      switch (pcbmd.action) {
  612.      case NUM:
  613.           memcpy(ranksuff  , tbuf, *tbuf );
  614.           parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  615.      default:
  616.           break;
  617.      }
  618.      /* PARAMETER 2A: Start-tag minimization.
  619.      */
  620.      TRACEMD("2A: start min");
  621.      switch (pcbmd.action) {
  622.      case CDR:
  623.           break;
  624.      case NAS:
  625.       if (!ustrcmp(tbuf+1, key[KO])) {
  626.            if (OMITTAG==YES) SET(fmin, SMO);
  627.            break;
  628.       }
  629.       /* fall through */
  630.      default:
  631.       if (OMITTAG==NO) {minomitted=1; break;}
  632.           mderr(129, tbuf+1, (UNCH *)0);
  633.           return;
  634.      }
  635.      /* Must omit omitted end-tag minimization, if omitted 
  636.     start-tag minimization was omitted (because OMITTAG == NO). */
  637.      if (!minomitted) {
  638.       /* PARAMETER 2B: End-tag minimization.
  639.        */
  640.       parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  641.       TRACEMD("2B: end min");
  642.       switch (pcbmd.action) {
  643.       case NAS:
  644.            if (ustrcmp(tbuf+1, key[KO])) {mderr(129, tbuf+1, (UNCH *)0); return;}
  645.            if (OMITTAG==YES) SET(fmin, EMO);
  646.       case CDR:
  647.            break;
  648.       default:
  649.            mderr(129, tbuf+1, (UNCH *)0);
  650.            return;
  651.       }
  652.       /* PARAMETER 3: Declared content.
  653.        */
  654.       parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  655.      }
  656.      TRACEMD("3: declared content");
  657.      switch (pcbmd.action) {
  658.      case NAS:
  659.           dctype = mapsrch(dctab, tbuf+1);
  660.           if (!dctype) {mderr(24, tbuf+1, (UNCH *)0); return;}
  661.           /* Eliminate incompatibilities among parameters. */
  662.           if (GET(fmin, SMO) && GET(dctype, MNONE+MCDATA+MRCDATA)) {
  663.                mderr(58, (UNCH *)0, (UNCH *)0);
  664.                RESET(fmin, SMO);
  665.           }
  666.           if (GET(dctype, MNONE) && BITOFF(fmin, EMO)) {
  667.            if (OMITTAG==YES) mderr(87, (UNCH *)0, (UNCH *)0);
  668.                SET(fmin, EMO);
  669.           }
  670.           /* If valid, process like a content model. */
  671.      case GRPS:
  672.           cmodsv = parsemod((int)(pcbmd.action==GRPS ? 0 : dctype));
  673.           if (cmodsv==0) return;
  674.       u = (dctype ? 1 : cmodsv->tu.tnum+2) * THSZ;
  675.           cmod = (struct thdr *)rmalloc(u);
  676.           memcpy((UNIV)cmod  , (UNIV)cmodsv, u );
  677.       ds.modcnt += cmod->tu.tnum;
  678.           TRACEMOD(cmod);
  679.           break;
  680.      default:
  681.           mderr(130, (UNCH *)0, (UNCH *)0);
  682.           return;
  683.      }
  684.      /* PARAMETERS 3A, 3B: Exceptions or end.
  685.      */
  686.      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  687.      if (BITOFF(cmod->ttype, MCDATA+MRCDATA+MNONE)) {
  688.           /* PARAMETER 3A: Minus exceptions.
  689.           */
  690.           TRACEMD("3A: -grp");
  691.           switch (pcbmd.action) {
  692.           case MGRP:
  693.            /* We cheat and use nnmgrp for this. */
  694.                mexgrp = copygrp((PETD *)nnmgrp,
  695.                 u = parsegrp((PETD *)nnmgrp, &pcbgrnm, tbuf));
  696.                ++ds.pmexgcnt; ds.pmexcnt += u-1;
  697.                TRACEGRP(mexgrp);
  698.                parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  699.           default:
  700.                break;
  701.           }
  702.           /* PARAMETER 3B: Plus exceptions.
  703.           */
  704.           TRACEMD("3B: +grp");
  705.           switch (pcbmd.action) {
  706.           case PGRP:
  707.                pexgrp = copygrp((PETD *)nnmgrp,
  708.                 u = parsegrp((PETD *)nnmgrp, &pcbgrnm, tbuf));
  709.                ++ds.pmexgcnt; ds.pmexcnt += u-1;
  710.                TRACEGRP(pexgrp);
  711.                parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  712.           default:
  713.                break;
  714.           }
  715.      }
  716.      /* PARAMETER 4: End of declaration.
  717.      */
  718.      TRACEMD(emd);
  719.      if (pcbmd.action!=EMD) mderr(126, (UNCH *)0, (UNCH *)0);
  720.      if (es!=mdessv) synerr(37, &pcbmd);
  721.  
  722.      /* EXECUTE: Store the definition for each element name specified.
  723.      */
  724.      TRACEGRP(nmgrp);
  725.      for (i = -1; nmgrp[++i];) {
  726.           etdgi = nmgrp[i]->etdgi;
  727.           if (*ranksuff) {
  728.                if ((tbuf[0] = *etdgi + ranksuff[0]-2)>NAMELEN) {
  729.                     mderr(131, etdgi+1, ranksuff+1);
  730.                     continue;
  731.                }
  732.                memcpy(tbuf+1, etdgi+1, *etdgi-1);
  733.                memcpy(tbuf+*etdgi-1  , ranksuff+1, *ranksuff-1 );
  734.                etdcan(etdgi);
  735.                nmgrp[i] = etddef(tbuf);
  736.           }
  737.           if (nmgrp[i]->etdmod) {mderr(56, etdgi+1, (UNCH *)0); continue;}
  738.           etdset(nmgrp[i], fmin+ETDDCL, cmod, mexgrp, pexgrp, nmgrp[i]->etdsrm);
  739.           ++ds.etdcnt;
  740.           if (nmgrp[i]->adl) etdadl(nmgrp[i]); /* Check ETD conflicts. */
  741.           TRACEETD(nmgrp[i]);
  742.      }
  743. }
  744. /*
  745. Local Variables:
  746. c-indent-level: 5
  747. c-continued-statement-offset: 5
  748. c-brace-offset: -5
  749. c-argdecl-indent: 0
  750. c-label-offset: -5
  751. End:
  752. */
  753.